
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include <semphr.h>

#include "stm32f10x.h"
#include "hw_config.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_exti.h"
#include "stm32f10x_rcc.h"
#include "misc.h"

// ----
#include "nrf24.h"
#include "ff.h"
#include "ffconf.h"
#include "pawn.h"


FATFS fs;

xSemaphoreHandle xSemaphore = NULL;

#define MAX_STRLEN 255                          // this is the maximum string length of our string in characters
volatile char RBUF[MAX_STRLEN+1];         // this will hold the recieved string
volatile char TBUF[MAX_STRLEN+1];         // this will hold the tranceived string
const char Ready[] = "\r\n/> ";

void console_hw_init()
{
    GPIO_InitTypeDef port;
    NVIC_InitTypeDef nvic;
    USART_InitTypeDef USART_InitStruct; 

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);         // enable APB2 peripheral clock for USART1

/******************** USART1 - console **************************************/
    // gpio
    GPIO_StructInit(&port);
    port.GPIO_Mode = GPIO_Mode_AF_PP;
    port.GPIO_Pin =  USART1_TX;
    port.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(USART1_GPIO, &port);
    // interrupt
    nvic.NVIC_IRQChannel = USART1_IRQn;                             // we want to configure the USART1 interrupts
    nvic.NVIC_IRQChannelPreemptionPriority = 10;            // this sets the priority group of the USART1 interrupts
    nvic.NVIC_IRQChannelSubPriority = 0;                        // this sets the subpriority inside the group
    nvic.NVIC_IRQChannelCmd = ENABLE;                                 // the USART1 interrupts are globally enabled
    NVIC_Init(&nvic);                                                                 // the properties are passed to the NVIC_Init function which takes care of the low level stuff   
    // usart
    USART_InitStruct.USART_BaudRate = 115200;                                        // the baudrate is set to the value we passed into this init function
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;            // we want the data frame size to be 8 bits (standard)
    USART_InitStruct.USART_StopBits = USART_StopBits_1;                        // we want 1 stop bit (standard)
    USART_InitStruct.USART_Parity = USART_Parity_No;                            // we don't want a parity bit (standard)
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // we don't want flow control (standard)
    USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;     // we want to enable the transmitter and the receiver
    USART_Init(USART1, &USART_InitStruct);                                                // again all the properties are passed to the USART_Init function which takes care of all the bit setting
    /* Here the USART1 receive interrupt is enabled and the interrupt controller is configured to jump to the USART1_IRQHandler() function
       if the USART1 receive interrupt occurs */
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                                 // enable the USART1 receive interrupt
    // finally this enables the complete USART1 peripheral
    USART_Cmd(USART1, ENABLE);
    
}

// Parcer function: Lightweight alternative to newlib atoi()
static int lightweight_atoi(const char *s) {
  int x = 0;

  while (*s)   {
    char c = *s++;

    if ((c >= '0') && (c <= '9'))
      x = x*10 + c - '0';
    else
      break;
  }

  return x;
}

static char* itoa_c(int value, char* result, int base)
{
    int tmp_value;
    char* ptr;
    char* ptr1;
    char tmp_char;
    
    // check that the base if valid
    if ( base < 2 || base > 36 ) {
        *result = '\0';
        return result;
    }
     
    ptr = ptr1 = result;
     
    do {
        tmp_value = value;
        value /= base;
        *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - value * base)];
    } while ( value );
     
    // Apply negative sign
    if ( tmp_value < 0 )
        *ptr++ = '-';
    *ptr-- = '\0';
     
    while ( ptr1 < ptr ) {
        tmp_char = *ptr;
        *ptr-- = *ptr1;
        *ptr1++ = tmp_char;
    }
     
    return result;
}

void USART_puts(USART_TypeDef* USARTx, volatile char *s)
{
    while(*s)
    { // wait until data register is empty
        while( !(USARTx->SR & 0x00000040) );
        USART_SendData(USARTx, *s);
        *s++;
    }
}

void USART_puts_u(USART_TypeDef* USARTx, TCHAR *s)
{
    while(*s)
    { // wait until data register is empty
        while( !(USARTx->SR & 0x00000040) );
        USART_SendData(USARTx, *s);
        *s++;
    }
}

void USART1_IRQHandler(void)
{
    static signed portBASE_TYPE xHigherPriorityTaskWoken; 

    xHigherPriorityTaskWoken = pdFALSE;
    
    if( USART_GetITStatus(USART1, USART_IT_RXNE) ) {          // check if the USART1 receive interrupt flag was set
        static uint8_t cnt = 0;                                                                // this counter is used to determine the string length
        char t = USART1->DR;                                                            // the character from the USART1 data register is saved in t
        
        if( (t != '\r') && (cnt < MAX_STRLEN) ) {                              // check if the received character is not the LF character (used to determine end of string)   * or the if the maximum string length has been been reached */
            RBUF[cnt] = t;
            USART1->DR = t;
            cnt++;
        } else { 
            cnt = 0;                                                                            // otherwise reset the character counter and print the received strin
            xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );
        }
    }
    
    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}

static void show_dir()
{
	FRESULT res;
	DIR dir;
	FILINFO fileinfo;
    const TCHAR d[] = _T("/"); 
#if _USE_LFN
    TCHAR lfn[_MAX_LFN + 1];
    fileinfo.lfname = lfn;
    fileinfo.lfsize = sizeof(lfn);
#endif

	res = f_opendir(&dir, d);
	if (res)
	{
		USART_puts(USART1, "Cannot open dir");
		return;
	}

	for(;;)
	{
		res = f_readdir(&dir, &fileinfo);
		if((res != FR_OK) || !fileinfo.fname[0])
			break;
        if(fileinfo.lfname[0] == 0) // short file name
            USART_puts_u(USART1, &(fileinfo.fname[0]));
        else
            USART_puts_u(USART1, &(fileinfo.lfname[0]));
        USART_puts(USART1, "\r\n");
	}
}


/* Here is the task for console */
void vTaskConsole(void *pvParameters)
{
    portBASE_TYPE xMoreDataToFollow;
    
    vTaskDelay( 1000 ); // Wait for HW init
    USART_puts(USART1, (volatile char *)Ready);
    vSemaphoreCreateBinary( xSemaphore );
    startNRF24();
    f_mount(&fs, _T("C:"), 1);
    for(;;){
        if( xSemaphoreTake( xSemaphore, 0xffff ) == pdTRUE ) {
            /* Process the input string received prior to the newline. */
            //do {
                /* Pass the string to FreeRTOS+CLI. */
                //xMoreDataToFollow = FreeRTOS_CLIProcessCommand( RBUF, TBUF, MAX_STRLEN );

                /* Send the output generated by the command's implementation. */
                //USART_puts(USART1, TBUF);
            //} while( xMoreDataToFollow != pdFALSE ); /* Until the command does not generate any more output. */
            //nrf24_ReadRegister(SPI2, RF_SETUP, (uint8_t *) RBUF, 1);
            //USART_puts(USART1, (volatile char *)itoa_c(RBUF[0], (char *)TBUF, 16));
            
            
            USART_puts(USART1, (volatile char *)Ready);
            //show_dir();
            PawnExec(_T("TEST1.AMX"));

        }
    }

    vTaskDelete(NULL);
}

